home *** CD-ROM | disk | FTP | other *** search
- // **********************************************
- // File: FORMAT.CPP
- // Musical text formatting functions
-
- #include "muzika.h"
- #include <alloc.h>
- #include <values.h>
-
- // **********************************************
- // FindMinDuration finds the minimum in a list and
- // returns its index. This function is used to find
- // the minimum duration of the next object among several staves.
-
- int FindMinDuration(int *duration, int multiplicity)
- {
- int min = MAXINT, minIndex;
- int *p = duration;
-
- while (multiplicity--) {
- if (min > *p) {
- min = *p;
- minIndex = p-duration;
- }
- ++p;
- }
-
- return minIndex;
- }
-
- // **********************************************
- // FormatMultipleStaff reformats a multiple staff.
- // This function is called once for every multiple staff in the part.
-
- void FormatMultipleStaff(int baseStaff)
- {
- // Create a few lists for use in the algorithm
- Part &p = *((Part *) &melody.part[displayedPart]);
- int *duration = (int *) malloc(p.multiplicity()*sizeof(int));
- int *index = (int *) malloc(p.multiplicity()*sizeof(int));
- BOOL *atCommon = (int *) malloc(p.multiplicity()*sizeof(BOOL));
- BOOL *staffEnd = (int *) malloc(p.multiplicity()*sizeof(BOOL));
- memset(duration, 0, p.multiplicity()*sizeof(int));
- memset(index, 0, p.multiplicity()*sizeof(int));
- memset(atCommon, 0, p.multiplicity()*sizeof(BOOL));
- memset(staffEnd, 0, p.multiplicity()*sizeof(BOOL));
- int X = 0;
- BOOL multipleEnd, multipleReached = FALSE;
-
- // Create unions of the continuousObject lists sorted by Xleft and Xright
- IndexedList sortedByLeft, sortedByRight;
- int leftIndex, rightIndex;
- for (int staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
- Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
- for (int orgIndex = 0; orgIndex < s.continuousObject.number(); ++orgIndex) {
- for (leftIndex = 0;
- leftIndex < sortedByLeft.number() &&
- ((ContinuousObject *) &sortedByLeft[leftIndex])->Xleft() <=
- ((ContinuousObject *) &s.continuousObject[orgIndex])->Xleft();
- ++leftIndex);
- sortedByLeft.insertAt(s.continuousObject[orgIndex], leftIndex);
- for (rightIndex = 0;
- rightIndex < sortedByRight.number() &&
- ((ContinuousObject *) &sortedByRight[rightIndex])->Xright() <=
- ((ContinuousObject *) &s.continuousObject[orgIndex])->Xright();
- ++rightIndex);
- sortedByRight.insertAt(s.continuousObject[orgIndex], rightIndex);
- }
- }
-
- // Loop as long as the end has not been reached on all staves
- do {
- // Find the staff with the minimum duration of the next object
- int minIndex = FindMinDuration(duration, p.multiplicity());
- int minDuration = duration[minIndex];
- int maxWidth = 0;
- multipleEnd = TRUE;
-
- // Subtract the minimum duration from all staves;
- // place the next object on the ones which reach 0 as a result
- for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
- Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
-
- if (atCommon[staffIndex] || !(duration[staffIndex] -= minDuration)) {
- // The next object duration has reached 0:
- // place the next object in the staff
- int currX = ((PointObject *) &s.pointObject[index[staffIndex]])->X();
- while (!(staffEnd[staffIndex] =
- index[staffIndex] == s.pointObject.number())) {
- PointObject &obj =
- *((PointObject *) &s.pointObject[index[staffIndex]]);
- if (obj.X() == currX) {
- if ((obj.location() & ~ONEPERSTAFF) == COMMONMULTIPLE) {
- // The object has a COMMONMULTIPLE location attribute:
- // mark the place and wait for other staves to reach
- // this object too
- atCommon[staffIndex] = !multipleReached;
- duration[staffIndex] = multipleReached ? 0 : MAXINT;
- if (!multipleReached)
- break;
- }
-
- // Reinitialize the next object duration
- if (duration[staffIndex] < obj.Duration())
- duration[staffIndex] = obj.Duration();
-
- // Call the object's Format virtual function,
- // in case the object wants to do something during formatting
- obj.Format(X);
- if (maxWidth < obj.Width())
- maxWidth = obj.Width();
- ++index[staffIndex];
-
- // Adjust the left and right coordinates
- // of any continuous objects that have been reached
- // while reformatting the point objects
- while (leftIndex < sortedByLeft.number() &&
- ((ContinuousObject *)
- &sortedByLeft[leftIndex])->Xleft() <= currX)
- ((ContinuousObject *)
- &sortedByLeft[leftIndex++])->FormatLeft(X);
- while (rightIndex < sortedByRight.number() &&
- ((ContinuousObject *)
- &sortedByRight[rightIndex])->Xright() <= currX)
- ((ContinuousObject *)
- &sortedByRight[rightIndex++])->FormatRight(X);
- }
- else break;
- }
- }
-
- // See if the end has been reached on all staves
- multipleEnd = multipleEnd && staffEnd[staffIndex];
- }
-
- // See if an object with a COMMONMULTIPLE location attribute
- // has been reached on all staves
- multipleReached = TRUE;
- for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex)
- multipleReached = multipleReached && atCommon[staffIndex];
-
- X += maxWidth;
- } while (!multipleEnd);
-
- // Free the continuous object list copies
- for (int i = sortedByLeft.number()-1; i >= 0; --i) {
- sortedByLeft.detachAt(i);
- sortedByRight.detachAt(i);
- }
-
- // Free all temporary lists on the heap
- free(staffEnd);
- free(atCommon);
- free(index);
- free(duration);
- }
-
- // **********************************************
- // FormatEntirePart reformats the displayed part
- // by calling FormatMultipleStaff once per every multiple staff
- // in the part.
-
- void FormatEntirePart()
- {
- Part &p = *((Part *) &melody.part[displayedPart]);
-
- // Call FormatMultipleStaff for every multiple staff in the part
- for (int index = 0; index < p.staff.number(); index += p.multiplicity())
- FormatMultipleStaff(index);
-
- // Mark the melody as modified and refresh screen
- melodyModified = TRUE;
- InvalidateRect(hEditWnd, NULL, TRUE);
- }
-